﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq.Expressions;
using System.Web;
using System.Web.Mvc;
using Ionic.Zip;
using MvcPresenter.Models;

namespace MvcPresenter
{
	/// <summary>
	/// プロバイダーファクトリなのでモデルに依存するのは
	/// 已む無しではないでしょうか。
	/// そうなるとモデルとの依存性のおかげで、namespaceとしてどこが
	/// 適切なのか皆目見当がつかなくなる．．．
	/// とりあえず、プロジェクトルートで。
	/// </summary>
	public class PresentationZipValueProviderFactory : ValueProviderFactory
	{

		private readonly List<string> _contentTypes = new List<string>
		                                              	{
		                                              		"application/zip",
		                                              		"application/x-zip-compressed"
		                                              	};

		public static string UploadTempPath
		{
			get
			{
				// ちゃんとSessionごとに一時フォルダを管理しましょう。
				return Path.Combine(Path.GetTempPath(), StorageAccessor.TempPathName);
			}
		}

		private Presentation UnzipToTemporary(HttpPostedFileBase postedFile)
		{
			if (!_contentTypes.Contains(postedFile.ContentType))
				return null;

			var fileName = Path.GetFileName(postedFile.FileName);
			var name = Path.GetFileNameWithoutExtension(fileName);
			if (!Directory.Exists(UploadTempPath))
				Directory.CreateDirectory(UploadTempPath);

			var savePath = Path.Combine(UploadTempPath, name);
			if (Directory.Exists(savePath))
				Directory.Delete(savePath, true);

			Directory.CreateDirectory(savePath);
			var filePath = Path.Combine(UploadTempPath, fileName);
			postedFile.SaveAs(filePath);

			using (var zip = ZipFile.Read(filePath))
			{
				zip.ExtractAll(savePath);
			}

			var presentation = StorageAccessor.Load(UploadTempPath, true, name);
			
			return presentation;
		}

		// 禁断のExpression
		private static void PresentationPropertyToDictionary<T>(IDictionary<string, object> dict,
		                                                        Expression<Func<IList<T>>> expression)
		{
			var memExp = expression.Body as MemberExpression;
            if (memExp == null)
                throw new ArgumentException("致命的！", "expression");

		    var propName = memExp.Member.Name;
			var list = expression.Compile().Invoke();
			for (var i = 0; i < list.Count; i++)
				dict[string.Format("{0}[{1}]", propName, i)] = list[i];
		}

		private static Dictionary<string, object> PresentationToDictionary(Presentation presentation)
		{
			var dict = new Dictionary<string, object>();

			dict["Name"] = presentation.Name;

			PresentationPropertyToDictionary(dict, () => presentation.Markups);
			PresentationPropertyToDictionary(dict, () => presentation.StyleSheets);
			PresentationPropertyToDictionary(dict, () => presentation.Images);

			return dict;
		}

		public override IValueProvider GetValueProvider(ControllerContext controllerContext)
		{
			if (controllerContext.HttpContext.Request.Files.Count == 0)
				return null;

			var postedFile = controllerContext.HttpContext.Request.Files[0];
			var presentation = UnzipToTemporary(postedFile);

			return new DictionaryValueProvider<object>(
				PresentationToDictionary(presentation), CultureInfo.CurrentCulture);
		}
	}
}